package edu.columbia.gate.plugins;

import gate.Annotation;
import gate.AnnotationSet;
import gate.Document;
import gate.DocumentContent;
import gate.FeatureMap;
import gate.SimpleAnnotation;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;

import java.util.*;

import gate.*;
import gate.corpora.DocumentContentImpl;
import gate.creole.*;
import gate.creole.gazetteer.AbstractGazetteer;
import gate.util.GateRuntimeException;
import gate.util.InvalidOffsetException;

public class DocumentRewriter extends AbstractLanguageAnalyser implements
		ProcessingResource
{

	public static final String TRANSD_DOCUMENT_PARAMETER_NAME = "document";

	public static final String ANNOTATION_SET_NAME_PARAMETER_NAME = "annotationSetName";

	protected String annotationSetName;

	/** Initialise this resource, and return it. */
	public Resource init() throws ResourceInstantiationException
	{
		return super.init();
	} // init()

	public void reInit() throws ResourceInstantiationException
	{
		init();
	} // reInit()

	/** Run the resource. */
	public void execute() throws ExecutionException
	{

		if (document == null)
			throw new GateRuntimeException("No document to process!");

		AnnotationSet annotSet = null;
		if (annotationSetName == null || annotationSetName.isEmpty())
		{
			annotSet = document.getAnnotations();
		} else
		{
			annotSet = document.getAnnotations(annotationSetName);
		}
		if (annotSet == null)
			throw new GateRuntimeException("Annotation set '"
					+ annotationSetName + "' was not found in the document.");

		Annotation[] annots = new Annotation[annotSet.size()];
		annotSet.toArray(annots);
		ArrayList<Annotation> annotsSorted = new ArrayList<Annotation>();
		for (int i = 0; i < annots.length; i++)
		{
			annotsSorted.add(annots[i]);
		}
		Collections.sort(annotsSorted, new AnnotationComparator());
		String newContent = this.document.getContent().toString();

		int offset = 0;
		long textStart, textEnd, lastTextStart = -1;
		ArrayList<ReplacedDocumentContent> replacedTexts = new ArrayList<ReplacedDocumentContent>(annotsSorted.size());
		
		for (int i = 0; i < annotsSorted.size(); i++)
		{
			SimpleAnnotation annot = (SimpleAnnotation) annotsSorted.get(i);
			FeatureMap features = annot.getFeatures();
			
			String entryMatched = ((String) features.get(EditDistanceGazetteer.FEATURE_NAME_ENTRY_MATCHED));
			
			textStart = annot.getStartNode().getOffset().intValue() + offset;
			if (entryMatched != null && textStart != lastTextStart)
			{
				String majorType = ((String) features.get(AbstractGazetteer.LOOKUP_MAJOR_TYPE_FEATURE_NAME));
				
				if(majorType == null) majorType="unkownMajorType"; 
				
				textEnd = annot.getEndNode().getOffset().intValue() + offset;
				String textInDoc = newContent.substring((int) textStart, (int) textEnd);
				newContent = newContent.substring((int) 0, (int) textStart) + entryMatched
						+ newContent.substring((int) textEnd);
				offset += entryMatched.length() - textInDoc.length();
				lastTextStart = textStart;
				
				replacedTexts.add(new ReplacedDocumentContent(textStart, textStart + entryMatched.length(), textInDoc, majorType));
			}
		}

		DocumentUtils.deleteAllAnnotations(document);

		DocumentUtils.replaceDocumentContent(document, newContent);

		
		// ADD ANNOTATIONS BACK
		for (ReplacedDocumentContent replacedText : replacedTexts)
		{
			FeatureMap newFeatures = (FeatureMap) Factory.newFeatureMap();
			newFeatures.put("originalText", replacedText.originalText);
			try
			{
				document.getAnnotations().add(replacedText.startOffset, replacedText.endOffset, replacedText.majorType, newFeatures);
			} 
			catch (InvalidOffsetException e)
			{
				// TODO Auto-generated catch block
				System.err.println("DocumentRewriter.execute - InvalidOffsetException: document.length=" + document.getContent().size() + ", replacedText is: " + replacedText.toString());
				e.printStackTrace();
			}
		}
	} // execute()

	public String getAnnotationSetName()
	{
		return this.annotationSetName;
	}

	public void setAnnotationSetName(String annotationSetName)
	{
		this.annotationSetName = annotationSetName;
	}

} // class AnnotationSetTransfer
